from decimal import Decimal
from django.utils import timezone
from rest_framework import serializers
from django_redis import get_redis_connection
from goods.models import SKU
from .models import OrderInfo, OrderGoods
from django.db import transaction
import logging

logger = logging.getLogger('django')



class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)

class SaveOrderSerializer(serializers.ModelSerializer):
    '''保存订单序列化器'''

    class Meta:
        model = OrderInfo
        fields = ('address', 'pay_method', 'order_id')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'pay_method': {
                'required': True
            },
            'address': {
                'required': True
            }
        }

    def create(self, validated_data):
        '''保存订单'''
        # 获取参数
        address = validated_data['address']
        pay_method = validated_data['pay_method']

        # 获取用户信息
        user = self.context['request'].user

        # 查询redis购物车数据 获取商品信息 sku_id count selected
        redis_conn = get_redis_connection('cart')

        # 获取商品数量信息
        redis_cart_dict = redis_conn.hgetall('cart_%s' % user.id)

        # 获取勾选的商品信息
        redis_cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)

        cart = {}

        for sku_id in redis_cart_selected:
            cart[int(sku_id)] = int(redis_cart_dict[sku_id])

        if not cart:
            raise serializers.ValidationError('没有要结算的商品')

        # 开启一个事务
        with transaction.atomic():

            # 创建一个保存点
            save_id = transaction.savepoint()

            try:
                # 自己生成一个订单编号
                order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

                # 保存商品订单数据 OrderInfo
                # 保存订单基本信息表数据
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.0'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                )

                # 获取商品的数据
                sku_id_list = cart.keys()
                # sku_obj_list = SKU.objects.filter(id__in=sku_id_list)

                # 遍历获取商品的数据
                for sku_id in sku_id_list:
                    # 判断商品库存
                    sku_count = cart[sku_id]

                    while True:
                        # 每次循环都去获取最新的数据值
                        sku = SKU.objects.get(id=sku_id)

                        # 记录原始库存
                        origin_stock = sku.stock
                        origin_salses = sku.sales

                        if origin_stock < sku_count:
                            # 库存量不足
                            # 回滚事务
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError('商品库存不足')

                        # import time
                        # time.sleep(5)

                        # 减少商品库存
                        new_stock = origin_stock - sku_count
                        # 增加商品销量
                        new_sales = origin_salses + sku_count
                        # sku.save()

                        # update返回收影响的行数
                        result = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock, sales=new_sales)

                        if result == 0:
                            # 表示更新失败
                            # 进行下一次while循环
                            continue

                        order.total_count += sku_count
                        order.total_amount += (sku.price * sku_count)

                        # 保存订单商品信息表数据OrderGoods
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price
                        )
                        break

                # 修改订单基本信息的累计数据
                order.save()
            except serializers.ValidationError:
                raise
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                raise
            else:
                # 提交事务
                transaction.savepoint_commit(save_id)

        # 删除购物车已结算商品数据
        pl = redis_conn.pipeline()

        # 删除商品数量
        pl.hdel('cart_%s' % user.id, *redis_cart_selected)

        # 删除勾选状态
        pl.srem('cart_selected_%s' % user.id, *redis_cart_selected)

        pl.execute()

        # 返回订单对象OrderInfo
        return order

